Skip to content

feat(mcp-core): Add snapshot inspection tools for LLM debugging#935

Merged
NicoHinderling merged 1 commit into
mainfrom
feat/snapshot-api-methods
May 14, 2026
Merged

feat(mcp-core): Add snapshot inspection tools for LLM debugging#935
NicoHinderling merged 1 commit into
mainfrom
feat/snapshot-api-methods

Conversation

@NicoHinderling
Copy link
Copy Markdown
Contributor

@NicoHinderling NicoHinderling commented May 6, 2026

Summary

Add MCP support for preprod snapshot inspection — LLMs can now browse snapshot builds, view comparison summaries, and fetch specific screenshot images to debug failed CI snapshot tests.

New public tools (+1)

  • get_latest_base_snapshot — Fetches the most recent base-build snapshot for a given app ID (+ optional branch). Returns compact image metadata (display_name, image_file_name, group) for browsing. Gated behind the preprod skill.

New internal tools (+1)

  • get_snapshot_details — Routes through get_sentry_resource via URL detection. Two modes:
    • Summary mode (default): Returns snapshot comparison summary with diff percentages, VCS context, approval status, and a compact image index
    • Image mode (when ?selectedSnapshot=<image_file_name> is in the URL): Fetches the actual image binary + full metadata, returned as ImageContent for multimodal LLMs

How get_sentry_resource routes snapshots

Snapshot URLs are auto-detected alongside issues, traces, replays, etc:

  • get_sentry_resource(url="https://sentry.sentry.io/preprod/snapshots/231949/") → summary + image index
  • get_sentry_resource(url="https://sentry.sentry.io/preprod/snapshots/231949/?selectedSnapshot=login_screen.png") → fetches actual image

This follows the same ?selectedSnapshot= pattern used by Sentry's UI, so URLs copy-pasted from the browser work directly.

New API client methods

Method Endpoint
getSnapshotDetails GET /api/0/organizations/{org}/preprodartifacts/snapshots/{id}/
getSnapshotImageDetail GET /api/0/organizations/{org}/preprodartifacts/snapshots/{id}/images/{identifier}/
getLatestBaseSnapshot GET /api/0/organizations/{org}/preprodartifacts/snapshots/latest-base/
fetchImageByUrl Fetches image binary from URL returned by image detail endpoint

Other changes

  • get_sentry_resource: Added project:read to requiredScopes (needed by internal snapshot handler), added preprod to skills list, added snapshot URL examples to description
  • URL parsing: parseSentryUrl now recognizes /preprod/snapshots/{id}/ URLs and extracts ?selectedSnapshot= query param, with unit tests
  • fetchImageByUrl hardening: Now handles absolute https:// URLs directly instead of routing through this.request() which would prepend the API base
  • Shared blobToBase64: Extracted to internal/blob-utils.ts using efficient Buffer.from().toString("base64"), replacing O(n^2) string concatenation in both get-snapshot-details and get-event-attachment
  • Agent allowlists: Added get_latest_base_snapshot to both sentry-mcp and sentry-mcp-experimental agent configs

Use cases covered

  1. CI failure triage: LLM receives a snapshot URL -> gets comparison summary with diff percentages -> views specific changed images
  2. Specific image inspection: LLM receives URL with ?selectedSnapshot= -> fetches image directly for visual analysis
  3. Browse latest screenshots: LLM calls get_latest_base_snapshot with app ID -> scans compact index -> views specific images via get_sentry_resource
  4. Investigate visual regressions: LLM gets snapshot URL -> reviews which images changed -> fetches them to understand the diff

Tool count

  • Before: 23 public tools
  • After: 24 public tools (+1: get_latest_base_snapshot), 3 internal tools (+1: get_snapshot_details)

@NicoHinderling NicoHinderling marked this pull request as ready for review May 6, 2026 22:02
Comment thread packages/mcp-core/src/tools/get-snapshot-image.ts Outdated
Comment thread packages/mcp-core/src/tools/get-snapshot-image.ts Outdated
Comment thread packages/mcp-core/src/api-client/client.ts Outdated
Comment thread packages/mcp-core/src/tools/get-snapshot-image.ts Outdated
@dcramer
Copy link
Copy Markdown
Member

dcramer commented May 6, 2026

A couple of quick thoughts (i didnt read code yet):

  1. we should only load snapshot related things if snapshots exist on the customer account
  2. we might need to push these behind e.g. get_sentry_resource etc (to minimize tool exposure) OR (especially if (1) cant be true) we might need to move these behind permission sets like seer is

@dcramer
Copy link
Copy Markdown
Member

dcramer commented May 6, 2026

do we need some kind of way to search for snapshots? not sure the workflows

@NicoHinderling
Copy link
Copy Markdown
Contributor Author

  1. we should only load snapshot related things if snapshots exist on the customer account

yes it's gated by their org token, so hopefully that's sufficient

  1. we might need to push these behind e.g. get_sentry_resource etc (to minimize tool exposure) OR (especially if (1) cant be true) we might need to move these behind permission sets like seer is

hmm im not familiar with either so i'll have to look into that

do we need some kind of way to search for snapshots? not sure the workflows

right now we're only building out the flow where the LLM knows the exact snapshot in question (ex. CI failure) but yeah that could be a logical next step

@dcramer
Copy link
Copy Markdown
Member

dcramer commented May 6, 2026

@NicoHinderling what do you mean by org token? the gates we have right now basically discover if the account is using a feature. you can prompt your agent to look for it and itll find it - but i believe we lock profiles and some other stuff behind that. its not critical if it uses shared tool definitions, but def valuable if we have no other choice but to expose more tools

Comment thread packages/mcp-core/src/internal/url-helpers.ts
Comment thread packages/mcp-core/src/tools/get-snapshot-image.ts Outdated
Comment thread packages/mcp-core/src/toolDefinitions.json Outdated
Comment thread packages/mcp-core/src/internal/url-helpers.ts
Comment thread packages/mcp-core/src/tools/get-snapshot-image.ts Outdated
Comment thread packages/mcp-core/src/tools/get-sentry-resource.ts
Comment thread packages/mcp-core/src/toolDefinitions.json Outdated
Comment thread packages/mcp-core/src/toolDefinitions.json Outdated
Comment thread packages/mcp-core/src/toolDefinitions.json Outdated
Comment thread packages/mcp-core/src/tools/get-snapshot-details.ts Outdated
@NicoHinderling NicoHinderling force-pushed the feat/snapshot-api-methods branch from 0b08058 to d4ca3ff Compare May 13, 2026 22:45
Comment thread packages/mcp-core/src/api-client/client.ts Outdated
Comment thread packages/mcp-core/src/tools/get-sentry-resource.ts
| "profile"
| "snapshot";

export interface ResolvedResourceParams {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol never realizaed how fucking ugly codex made this

will clean it up at some point and put in a proper union


result.hint = `To view a specific image, use get_sentry_resource(url="${resolvedSnapshotUrl}?selectedSnapshot=<image_file_name>").`;

return JSON.stringify(result, null, 2);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really feel json is the best output here? we try to curate the responses in most of the MCP so they're useful, vs just being effectively an API proxy

Comment thread packages/mcp-core/src/api-client/client.ts
@NicoHinderling NicoHinderling force-pushed the feat/snapshot-api-methods branch 2 times, most recently from 300ed52 to 2a7962a Compare May 13, 2026 23:08
Comment thread packages/mcp-core/src/tools/get-latest-base-snapshot.ts
Comment thread packages/mcp-core/src/internal/url-helpers.ts
…napshots

Adds two tools for preprod snapshot support:
- `get_latest_base_snapshot` (public): Fetches the most recent base-build snapshot for an app, returning compact image metadata for browsing
- `get_snapshot_details` (internal): Returns snapshot comparison summaries with diff info, and fetches specific images when `selectedSnapshot` is provided

Snapshot image viewing is consolidated behind `get_sentry_resource` using the `?selectedSnapshot=<image_file_name>` URL pattern from Sentry's UI, avoiding a separate public tool.

Also includes: shared `blobToBase64` utility using efficient `Buffer.from()`, snapshot URL parsing with unit tests, `project:read` scope on `get_sentry_resource`, and absolute URL guard in `fetchImageByUrl`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@NicoHinderling NicoHinderling force-pushed the feat/snapshot-api-methods branch from 2a7962a to 196881e Compare May 13, 2026 23:19
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 196881e. Configure here.

}

sections.push(
`\n## Next Steps\n\n- To view a specific image, use \`get_sentry_resource(url="${resolvedSnapshotUrl}?selectedSnapshot=<image_file_name>")\``,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Next Steps URL broken when snapshot URL has query params

Low Severity

The "Next Steps" template naively appends ?selectedSnapshot= to resolvedSnapshotUrl. If the input snapshotUrl already contains query parameters (e.g. tracking params or other state from a browser-copied URL), this produces a URL with two ? characters, making it invalid. The second ? needs to be & when query params already exist.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 196881e. Configure here.

? ` — file: \`${img.image_file_name}\``
: "";
sections.push(`- \`${name}\`${group}${file}`);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image formatting logic duplicated across two files

Low Severity

The image line formatting logic (display_name fallback, group suffix, conditional file: annotation) is identically implemented inline in get-latest-base-snapshot.ts and as formatImageLine/getImageDisplayName helpers in get-snapshot-details.ts. These could diverge if one is updated without the other. Extracting to a shared utility (e.g. alongside blobToBase64 in the internal/ directory) would keep them in sync.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 196881e. Configure here.

@NicoHinderling NicoHinderling merged commit 42f1442 into main May 14, 2026
17 checks passed
@NicoHinderling NicoHinderling deleted the feat/snapshot-api-methods branch May 14, 2026 02:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants